package data

import (
	"lnzw/common/math"
	"lnzw/common/proto/rpc_gen"
	"lnzw/engine/actor"
	"lnzw/engine/aoi/crosslinks"
	"lnzw/engine/log"

	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
)

var MapCatalog = "map"

type Map struct {
	crosslinks.Grid
	actor.DefaultActor
	width, height int
	units         map[int64]IUnit
	pnum          int
	mnum          int
}

func (m *Map) GetWidth() int {
	return m.width
}

func (m *Map) GetHeight() int {
	return m.height
}

func (m *Map) GetCellSize() int {
	return 10
}

func (m *Map) GetUnit(id int64) IUnit {
	return m.units[id]
}

func (b *Map) Watch(u IUnit) []IUnit {
	return b.WatchFree(u, u.GetViewRange())
}

func (b *Map) WatchFree(u IUnit, rangew int) []IUnit {
	entitiesInRange := b.Grid.GetEntitiesInRange(u, rangew)
	units := make([]IUnit, 0, len(entitiesInRange))
	for _, entity := range entitiesInRange {
		if unit, ok := entity.(IUnit); ok {
			if unit.GetUnitId() == u.GetUnitId() {
				continue
			}
			units = append(units, unit)
		}
	}
	return units
}

func (m *Map) EnterMap(unit IUnit) {
	m.AddEntity(unit.(crosslinks.Entity))
	m.units[unit.GetUnitId()] = unit
	unit.OnEnterMap(m)
	if unit.GetUnitType() == Player {
		m.pnum++
	}
	if unit.GetUnitType() == Monster {
		m.mnum++
	}
}

func (m *Map) LeaveMap(unit IUnit) {
	m.RemoveEntity(unit.(crosslinks.Entity))
	delete(m.units, unit.GetUnitId())
	if unit.GetUnitType() == Player {
		m.pnum--
	}
	if unit.GetUnitType() == Monster {
		m.mnum--
	}
}

func (m *Map) MoveTo(unit IUnit, x, y int) {
	m.MoveEntity(unit.(crosslinks.Entity), crosslinks.Point{X: float32(x), Y: float32(y)})
}

func (m *Map) UnitsNum() int {
	return len(m.units)
}

func (m *Map) GetPlayerNum() int {
	return m.pnum
}
func (m *Map) GetMonsterNum() int {
	return m.mnum
}

func (m *Map) RandPosition() (x, y int) {
	width := m.Width
	height := m.Height
	x = math.RandBetween(0, width)/m.GetCellSize()*m.GetCellSize() + Offset
	y = math.RandBetween(0, height)/m.GetCellSize()*m.GetCellSize() + Offset
	return
}

// 玩家处理函数
func (p *Map) Handle(msg actor.Msg) {
	var rpcmsg rpc_gen.MapMessage
	err := proto.Unmarshal(msg.Data, &rpcmsg)
	if err != nil {
		log.Error("proto.Unmarshal", zap.Any("err", err))
		return
	}
	switch rpcmsg.Mmt {
	case rpc_gen.MapMessageType_MMT_MAP_MOVE:
	}
}

func (p *Map) StartMap(width, height int) {
	p.Grid = *crosslinks.NewGrid(width, height)
	p.width = width
	p.height = height
	p.units = make(map[int64]IUnit)
}

func NewMap() actor.IActor {
	return &Map{}
}
